package tcp;

// 编写 TCP 版本的 echo server
// TCP是需要建立连接的:客户端请求与服务器建立连接
// 注意Socket 与 ServerSocket的使用： ServerSocket是用在外场监听

// 版本2：多线程使用：会有多次创建、销毁问题！

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

public class TcpEchoServer2 {
    // 设置一个监听器:针对服务器！
    private ServerSocket listenSocket = null;

    // 构造方法：
    public TcpEchoServer2(int port) throws IOException {
        listenSocket = new ServerSocket(port);
    }

    // 启动服务器
    public void start() throws IOException {
        // 处理请求
        System.out.println("启动服务器！");
        while (true) {
            // 1. 调用accept来接受客户端的连接
            Socket clientSocket = listenSocket.accept();

            // 2.处理该连接-多线程
            Thread t = new Thread(() -> {
                try {
                    processConnection(clientSocket);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            });
            t.start(); //一定要启动线程！
        }
    }

    private void processConnection(Socket clientSocket) throws IOException {
        // 就类似于udp的处理
        System.out.printf("[%s:%d] 客户端上线！\n",clientSocket.getInetAddress().toString(),
                clientSocket.getPort());
        // 流输入/输出
        try(InputStream inputStream = clientSocket.getInputStream();
            OutputStream outputStream = clientSocket.getOutputStream()) {
            while (true) {
                // 1.读取请求并解析
                Scanner scanner = new Scanner(inputStream); // 流读取
                if (!scanner.hasNext()) { // 只是单纯进行判断是否读完，不用使用循环
                    // 读完了,断开连接
                    System.out.printf("[%s:%d] 客户端下线\n",clientSocket.getInetAddress().toString(),
                            clientSocket.getPort());
                    break;
                }
                String request = scanner.next();

                // 2. 根据请求计算响应
                String response = process(request);

                // 3. 将响应写回到客户端
                PrintWriter printWriter = new PrintWriter(outputStream);
                printWriter.println(response);
                // 要进行刷新
                printWriter.flush();

                // 4.打印日志
                System.out.printf("[%s:%d] req:%s; resp:%s\n",clientSocket.getInetAddress().toString(),
                        clientSocket.getPort(),request,response);

            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 每次都会创建clientSocket，所以此处使用完进行关闭
            clientSocket.close();
        }
    }

    private String process(String request) {
        return request;
    }

    public static void main(String[] args) throws IOException {
        TcpEchoServer2 server = new TcpEchoServer2(9092);
        server.start();
    }

}
